package app

import (
	"github.com/dgrijalva/jwt-go"
	"go-programming-tour-book/blog_service/global"
	"go-programming-tour-book/blog_service/pkg/util"
	"time"
)

// Claims 分为两大块
// 第一块：AppKey 和 AppSecret，用于我们自定义的认证信息
// 第二块：jwt.StandardClaims，它是在 jwt-go 库中预定义的
type Claims struct {
	AppKey    string `json:"app_key,omitempty"`
	AppSecret string `json:"app_secret,omitempty"`
	jwt.StandardClaims
}

// GetJWTSecret 获取项目的 JWT Secret，目前我们使用的是默认配置的 Secret
func GetJWTSecret() []byte {
	return []byte(global.JWTSetting.Secret)
}

// GenerateToken 生成 JWT Token
func GenerateToken(appKey, appSecret string) (string, error) {
	nowTime := time.Now()
	expireTime := nowTime.Add(global.JWTSetting.Expire)
	claims := Claims{
		AppKey:    util.EncodeMD5(appKey),
		AppSecret: util.EncodeMD5(appSecret),
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    global.JWTSetting.Issuer,
		},
	}

	//NewWithClaims 根据 Claims 结构体创建 Token 实例
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	//SignedString 生成签名字符串，根据传入的 Secret，进行签名并返回标准的 Token
	token, err := tokenClaims.SignedString(GetJWTSecret())
	return token, err
}

// ParseToken 解析和校验 Token
func ParseToken(token string) (*Claims, error) {
	//ParseWithClaims 解析鉴权的声明，最终返回 *Token
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return GetJWTSecret(), nil
	})
	if tokenClaims != nil {
		Claims, ok := tokenClaims.Claims.(*Claims)
		//验证基于时间的声明，如过期时间（ExpiresAt）、签发者（Issuer）、生效时间。
		//注意：即便在令牌中没有任何声明，也仍然被认为是有效的
		if ok && tokenClaims.Valid {
			return Claims, nil
		}
	}
	return nil, err
}
